<?php

namespace app\common\model;

use app\common\library\Upload;
use ba\Random;
use think\facade\Cache;
use think\facade\Db;
use think\facade\Log;
use think\Model;

/**
 * 会员公共模型
 * @property int    $id              会员ID
 * @property string $password        密码密文
 * @property string $salt            密码盐
 * @property int    $login_failure   登录失败次数
 * @property string $last_login_time 上次登录时间
 * @property string $last_login_ip   上次登录IP
 * @property string $email           会员邮箱
 * @property string $mobile          会员手机号
 */
class User extends Model
{
    const TABLE_NUM = 10;

    protected $autoWriteTimestamp = true;

    /**
     * 上传类实例，可以通过它调用上传文件驱动，且驱动类具有静态缓存
     */
    protected static Upload $upload;

    protected $type = [
        'id'    =>  'string',
    ];

    protected static function init(): void
    {
        self::$upload = new Upload();
    }

    public function getAvatarAttr($value): string
    {
        if ($value) {
            //检查$value是否带有完整的域名，如过是path的话$domain设置为false，反之设置为true
            $parsed = parse_url($value);
            $domain = isset($parsed['scheme']) && isset($parsed['host']);
            if (!$domain) {
                $conf = get_upload_config();
                $driver = self::$upload->getDriver($conf['mode'], false);
                return $driver ? $driver->signUrl($value, 31536003) : full_url($value, false, config('buildadmin.default_avatar'));
            }
            return full_url($value, $domain, config('buildadmin.default_avatar'));
        }

        return config('app.app_host').full_url($value, false, config('buildadmin.default_avatar'));
    }

    public function setAvatarAttr($value): string
    {
        $value = prepare_file_path($value);
        return $value == full_url('', false, config('buildadmin.default_avatar')) ? '' : $value;
    }

    public function resetPassword($uid, $newPassword): int|User
    {
        $salt   = Random::build('alnum', 16);
        $passwd = encrypt_password($newPassword, $salt);
        return $this->where(['id' => $uid])->update(['password' => $passwd, 'salt' => $salt]);
    }

    public function getMoneyAttr($value): string
    {
        return bcdiv($value, 100, 2);
    }

    /**
     * 用户的余额是不可以直接进行修改的，请通过 UserMoneyLog 模型插入记录来实现自动修改余额
     * 此处定义上 money 的修改器仅为防止直接对余额的修改造成数据错乱
     */
    public function setMoneyAttr($value): string
    {
        return bcmul($value, 100, 2);
    }

    /**
     * 如果表不存在，则创建新表
     *
     */
    public function createTableIfNotExists($tableName): bool
    {
        $cacheKey = 'makeTable:'.$tableName;
        $check = Cache::get($cacheKey);
        if ($check) {
            return true;
        }
        // 检查表是否存在
        $exists = Db::query("SHOW TABLES LIKE  '{$tableName}'");

        if (!$exists) {
            $sql = <<<SQL
            CREATE TABLE `{$tableName}` (
              `id` int(10) unsigned NOT NULL AUTO_INCREMENT COMMENT 'ID',
              `group_id` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '分组ID',
              `username` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '用户名',
              `nickname` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '昵称',
              `email` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '邮箱',
              `mobile` varchar(11) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '手机',
              `avatar` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '头像',
              `gender` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '性别:0=未知,1=男,2=女',
              `birthday` date DEFAULT NULL COMMENT '生日',
              `money` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '余额',
              `score` int(10) unsigned NOT NULL DEFAULT '0' COMMENT '积分',
              `last_login_time` bigint(20) unsigned DEFAULT NULL COMMENT '上次登录时间',
              `last_login_ip` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '上次登录IP',
              `login_failure` tinyint(3) unsigned NOT NULL DEFAULT '0' COMMENT '登录失败次数',
              `join_ip` varchar(50) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '加入IP',
              `join_time` bigint(20) unsigned DEFAULT NULL COMMENT '加入时间',
              `motto` varchar(255) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '签名',
              `password` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '密码',
              `salt` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '密码盐',
              `temp_code` varchar(32) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '临时码：客户端指纹',
              `account_type` tinyint(1) NOT NULL DEFAULT '0' COMMENT '平台：0-游客  1-email 2-Facebook 3-google',
              `status` varchar(30) COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '' COMMENT '状态',
              `update_time` bigint(20) unsigned DEFAULT NULL COMMENT '更新时间',
              `create_time` bigint(20) unsigned DEFAULT NULL COMMENT '创建时间',
              PRIMARY KEY (`id`) USING BTREE,
              UNIQUE KEY `username` (`username`) USING BTREE
            ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci COMMENT='会员表';
        SQL;

            try {
                Db::execute($sql);
            } catch (\Exception $e) {
                // 记录异常信息
                Log::channel('my')->error("Failed to create table {$tableName}: " . $e->getMessage());
                // 可以选择抛出异常或返回错误信息
                throw new \RuntimeException("Failed to create table: " . $e->getMessage(), 0, $e);
            }

        }
        Cache::set($cacheKey, 1);

        return true;
    }

    /**
     * 初始化用户模型
     *
     * 此方法用于创建并返回一个新的User对象实例
     * 它是一个静态方法，可以在不实例化类的情况下直接调用
     *
     * @return User 新创建的User对象实例
     */
    public static function initModel($tempCode = ""): User
    {
        //使用这个方法实例化，方便拓展分表逻辑
        $model = new static();
        if ($tempCode) {
            $hashValue = crc32($tempCode); // 计算字符串的哈希值
            $tableName = 'user_' . ($hashValue % self::TABLE_NUM);
            $model->setName($tableName);
            $prefix = config('database.connections.mysql.prefix');
            $model->createTableIfNotExists($prefix . $tableName);
        }
        return $model;
    }
}